﻿// ***********************************************************************
// Provided for Informational Purposes Only
//
// Apache 2.0 License
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 
// PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.
// ***********************************************************************
// Assembly  : ContractMeow.Models
// File      : Thread.cs
//
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;



namespace ContractMeow.Models
{
	public sealed class Thread
	{
		private object _updateThreadSync = new object();

		public Int64 Id { get; set; }

		private Group _group;
		public Group Group
		{
			get { return _group; }
			set
			{
				_group = value;
			}
		}

		public String GroupName
		{
			get
			{
				//todo: localization;
				return Group == null
						   ? "All company"
						   : Group.FullName;
			}
		}

		private Int32 _messageCount;
		public Int32 MessageCount
		{
			get { return _messageCount; }
			set
			{
				_messageCount = value;
			}
		}

		public Int32 ReplyCount
		{
			get
			{
				return MessageCount <= 0
						   ? 0
						   : MessageCount - 1;
			}
		}

		private Message _post;
		public Message Post
		{
			get { return _post; }
			set
			{
				_post = value;
			}
		}

		private Dictionary<long, Message> _replyLookup;
		private Dictionary<long, Message> ReplyLookup
		{
			get
			{
				if (_replyLookup != null)
					return _replyLookup;

				_replyLookup = Replies == null ? new Dictionary<long, Message>() : Replies.ToDictionary(r => r.Id);

				return _replyLookup;
			}
		}

		private List<Message> _replies;
		public List<Message> Replies
		{
			get { return _replies; }
			set
			{
				_replies = value;
			}
		}

		private bool HasMessage(long replyId)
		{
			return ReplyLookup.ContainsKey(replyId);
		}

		public Message LatestReply
		{
			get
			{
				return Replies != null
						   ? Replies.LastOrDefault()
						   : null;
			}
		}

		/// <value><c>true</c> if the main post of this thread has attachments; otherwise, <c>false</c>.</value>
		public bool HasAttachments
		{
			get { return _post.HasAttachments || _post.HasFileAttachments; }
		}

		public void PrependReplies(IList<Message> olderReplies)
		{
			lock (_updateThreadSync)
			{
				foreach (var message in olderReplies)
				{
					if (HasMessage(message.Id))
						continue;

					Replies.Insert(0, message);
				}
			}
		}

		public void AppendReplies(IList<Message> newReplies)
		{
			var repliesToAdd = new List<Message>();

			// Make sure we synchronize access to the replies structure to avoid
			// duplicated data (race conditions)
			lock (_updateThreadSync)
			{
				// for is faster than foreach and since these may run
				// in low power devices and we may potentially have more
				// than a dozen items, it's safer to go the long route.
				for (var index = newReplies.Count - 1; index >= 0; index--)
				{
					var reply = newReplies[index];
					//Update reply list and count
					//prevent duplication of items in replies list
					if (HasMessage(reply.Id))
						continue;

					repliesToAdd.Add(reply);
				}

				Replies.AddRange(repliesToAdd);
				MessageCount += repliesToAdd.Count;
			}
		}
	}
}